<script>
     /*
                四、如何处理和解决死锁？

                         死锁无法完全解决，但可以通过一系列措施来最大限度地减少其发生频率和影响。

                         1、即时处理：SQL Server 自动处理

                                        SQL Server 有一个内置的 "死锁监视器" 线程，它定期检查系统是否有死锁.
                                        
                                        一旦检测到死锁，它会选择一个代价最小的事务作为 "牺牲品"，将其回滚并向应用程序抛出 "1205" 错误，从而让另一个事物可以继续运行。

                                        作为开发者，你的应用程序 "必须能够捕获并处理 1205错误"，通常的策略是：

                                                ①、记录错误信息

                                                ②、等待一小段时间

                                                ③、自动重试整个事务 (通常最多重试3次)

                         2、调查与分析： 捕获死锁信息

                                        要解决问题，首先要知道死锁是如何发生的。

                                        <1>、开启跟踪标志 (传统方法)：

                                                sql语句：

                                                        DBCC TRACEON(1222,-1)DBCC TRACEON (1222, -1) -- 将死锁信息输出到错误日志
                                                        DBCC TRACEON (1204, -1) -- 提供更详细的死锁信息

                                        <2>、使用Sql Server Profile (SSMS工具)：

                                                创建一个跟踪，捕获 Deadlock graph 事件。

                                                它会提供一个图形化界面，清晰展示哪些事务参与了死锁、它们争夺的资源是什么以及谁被选择了牺牲品。

                                        <3>、使用扩展事件 (Extended Events,推荐方法)

                                                大的现代方法。可以创建一个扩展事件会话来捕获 xml_deadlock_report 事件，将死锁信息保存到文件或表中，便于后续分析。


                         3、根本性预防与优化

                                        <1>、保持一致的访问顺序：

                                                在应用程序代码中，规定所有事务对多个对象的访问都按照相同的顺序（例如，先表A，再表B）。这可以打破“循环等待”条件。

                                        <2>、创建有效的索引：

                                                分析死锁图形和执行计划，检查是否因为全表扫描导致锁升级。添加合适的索引可以缩小锁定范围，减少锁冲突。

                                        <3>、缩短事务长度：

                                                ①、事务应尽可能短小精悍。

                                                ②、不要在事务中执行用户交互（如等待用户确认），这会使锁保持很长时间。

                                                ③、将不必要的 SELECT 语句移到事务外，只在事务中包含最必要的 INSERT/UPDATE/DELETE 操作。

                                        <4>、使用较低的隔离级别：

                                                默认的 READ COMMITTED 隔离级别在读取后就会释放共享锁。、

                                                如果业务允许，可以考虑使用 READ COMMITTED SNAPSHOT 或 SNAPSHOT ISOLATION，它们通过行版本控制来实现读一致性，
                                                
                                                读者不会阻塞写者，写者也不会阻塞读者，从而从根本上减少很多死锁场景。

                                        <5>、使用提示（Hints）精细化控制锁行为（谨慎使用）

                                                ①、ROWLOCK：强制使用行级锁，避免锁升级。

                                                ②、UPDLOCK：在读取时使用更新锁（U锁），提示数据库你即将要更新该行，防止其他事务获取该行的U锁或X锁。

                                                ③、NOLOCK：脏读，仅用于非常不重要的统计场景，风险极高，一般不推荐。

                                                ④、READPAST：跳过已被锁定的行，适用于高并发队列处理。

                                                注意： 锁提示是一把双刃剑，使用不当可能会引发其他问题或降低并发性。
            */
</script>